package cn.itsource.hrm.service.impl;

import cn.itsource.dto.SMSSendLogDTO;
import cn.itsource.hrm.dto.SendSMSCodeDTO;
import cn.itsource.hrm.exception.Assert;
import cn.itsource.hrm.exception.BusinessException;
import cn.itsource.hrm.service.IVerifyCodeService;
import cn.itsource.hrm.util.StrUtils;
import cn.itsource.hrm.util.VerifyCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
public class VerifyCodeServiceImpl implements IVerifyCodeService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    /**
     * 图片验证码
     * 1.参数判断
     * 2.创建一个6位的随机字符串：图片验证码  xoxo
     * 3.把图片验证码存储到Redis：使用前端传入的key
     * 4.把验证码xoxo生成到一个图片上:工具
     * 5.把图片变成Bae64编码的字符串，把字符串返回
     * @param key ：redis的key
     * @return
     */
    @Override
    public String createImageCode(String key) {
        //* 1.参数判断
        Assert.assertNotEmpty(key,"非法请求");
        //* 2.创建一个6位的随机字符串：图片验证码  xoxo
        String code = StrUtils.getComplexRandomString(6);
        //* 3.把图片验证码存储到Redis：使用前端传入的key
        redisTemplate.opsForValue().set(key , code ,5 , TimeUnit.MINUTES);
        try {
            //* 4.把验证码xoxo生成到一个图片上:工具
            //* 5.把图片变成Bae64编码的字符串，把字符串返回
            return VerifyCodeUtils.verifyCode(130, 35, code);
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 短信验证码
     * 1.校验参数(参数：手机号，key,图片验证码)
     * 2.校验图片验证码必须正确：去Redis中查询
     *
     * 3.尝试获取上一次发送记录
     *
     * 4.如果有：
     * 4.1.当前时间-上次发送时间必须大于60s
     * 4.2.小于60s,报错，发送太频繁
     * 4.3.满足条件：使用上一次的验证码
     *
     * 5.如果么有：创建短信验证码
     *
     * 6.短信验证码存储到Redis，设置过期时间
     *    key是什么？value是什么？
     *    使用手机号作为:  sms:phone ， value：时间，验证码
     * 7.调用短信网关发送短信验证码
     * 8.数据库存储短信验证码发送记录
     * @param dto ：参数对象
     */
    @Override
    public void sendSMSCode(SendSMSCodeDTO dto) {
        //* 1.校验参数(参数：手机号，key,图片验证码)
        String imageCode = dto.getImageCode();
        String imageCodeKey = dto.getImageCodeKey();
        String mobile = dto.getMobile();
        //* 2.校验图片验证码必须正确：去Redis中查询
        String imageCodeFromRedis = (String)redisTemplate.opsForValue().get(imageCodeKey);
        Assert.assertNotEmpty(imageCodeFromRedis,"无效的图片验证码或已过期");
        if(!imageCodeFromRedis.equalsIgnoreCase(imageCode)){
            throw new BusinessException("图片验证码错误");
        }
        //* 3.尝试获取上一次发送记录
        String smsCodeKey =  "sms:"+mobile;
        SMSSendLogDTO lastSendDTO = (SMSSendLogDTO) redisTemplate.opsForValue().get(smsCodeKey);

        String smsCode = null;
        Date now = new Date();

        if(lastSendDTO != null){
            //* 4.如果有：
            //* 4.1.当前时间-上次发送时间必须大于60s
            if((now.getTime() - lastSendDTO.getSendTime()) / 1000 < 60 ){
                //* 4.2.小于60s,报错，发送太频繁
                throw new BusinessException("老铁单身吧，手速太快，骚后再来");
            }
            //* 4.3.满足条件：使用上一次的验证码
            smsCode = lastSendDTO.getSmsCode();
        }else{
            //* 5.如果么有：创建短信验证码
            smsCode = StrUtils.getRandomString(6);
        }
        //* 6.短信验证码存储到Redis，设置过期时间
        //*    使用手机号作为:  sms:phone ， value：时间，验证码
        SMSSendLogDTO smsSendLogDTO = new SMSSendLogDTO(smsCode, now.getTime());
        redisTemplate.opsForValue().set(smsCodeKey ,smsSendLogDTO , 6,TimeUnit.MINUTES );
        //* 7.调用短信网关发送短信验证码
        log.info("发送短信验证码 {} ",smsCode);
        //TODO : 把项目二的代码拿过来
        //* 8.数据库存储短信验证码发送记录 ： 时间 ；验证码 ；手机号 ；IP ； 类型(什么短信) ；状态
        //TODO
        log.info("保存一个短信发送记录到DB");
    }
}
